package com.spzx.report.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.report.constant.PineconeConst;
import com.spzx.report.entity.VOrderInfo;
import com.spzx.report.entity.VOrderInfoJsonObject;
import com.spzx.report.mapper.VOrderInfoMapper;
import com.spzx.report.service.SpzxReportService;
import com.spzx.report.utils.chat.SpzxAiQuest;
import com.spzx.report.utils.embedding.PineconeSimilarlyUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * Package: com.spzx.report.service.impl
 *
 * @author xiongkunYang
 * @description:
 * @since 2025/6/11 9:27
 */
@Service
public class SpzxReportServiceImpl extends ServiceImpl<VOrderInfoMapper, VOrderInfo> implements SpzxReportService {

    private final RedisTemplate<Object, Object> redisTemplate;
    private final ThreadPoolExecutor threadPoolExecutor;

    public SpzxReportServiceImpl(RedisTemplate<Object, Object> redisTemplate, ThreadPoolExecutor threadPoolExecutor) {
        this.redisTemplate = redisTemplate;
        this.threadPoolExecutor = threadPoolExecutor;
    }


    /**
     * 第一步，调用AI模型解析用户输入的问题为JSON格式，并将解析结果存储在Redis中以供后续使用
     *
     * @param question 用户输入的问题字符串
     * @return 包含缓存键、关键词数量和关键词组的映射
     */
    @Override
    public Map<String, String> analyzeQuestion(String question) {
        // 创建SpzxAiQuest实例以处理问题
        SpzxAiQuest spzxAiQuest = new SpzxAiQuest();
        // 调用AI模型处理问题，返回JSON格式的答案
        String answerJson = spzxAiQuest.processQuestion(question);
        // 将JSON答案解析为VOrderInfoJsonObject对象
        VOrderInfoJsonObject vOrderInfoJsonObject = JSON.parseObject(answerJson, VOrderInfoJsonObject.class);

        // 生成唯一的Redis键用于存储AI报告
        String cacheKey = "ai_report:" + UUID.randomUUID();

        // 将解析后的对象存储在Redis中，设置过期时间为5分钟
        redisTemplate.opsForValue().set(cacheKey, vOrderInfoJsonObject, 5, TimeUnit.MINUTES);

        // 返回包含缓存键、关键词数量和关键词组的映射
        return Map.of(
                "cacheKey", cacheKey,
                "countKeyword", vOrderInfoJsonObject.getCountKeyword(),
                "groupKeyword", vOrderInfoJsonObject.getGroupKeyword()
        );
    }


    /**
     * 第二步：根据 key 获取缓存数据并生成报表
     *
     * @param cacheKey 缓存数据的唯一键
     * @return 报表数据
     */
    @Override
    public Map<String, Object> generateReport(String cacheKey) {
        // 从 Redis 获取缓存数据
        VOrderInfoJsonObject vOrderInfoJsonObject = (VOrderInfoJsonObject) redisTemplate.opsForValue().get(cacheKey);
        if (vOrderInfoJsonObject == null) {
            throw new ServiceException("缓存已过期或不存在，请重新发起请求");
        }
        // 用向量数据库匹配相似工具，匹配ai过滤关键词，获得元数据(word和column)，作为拼接报表sql的具体字段和条件数据
        VOrderInfoJsonObject vectorData = this.getVectorData(vOrderInfoJsonObject);

        // 构造查询条件并执行数据库查询
        QueryWrapper<VOrderInfo> vOrderInfoQueryWrapper = this.getReportWrapper(new QueryWrapper<>(), vectorData);
        List<Map<String, Object>> reportMaps = this.baseMapper.selectMaps(vOrderInfoQueryWrapper);
        Map<String, Object> xyMap = new HashMap<>();
        List<String> xList = new ArrayList<>();
        List<String> yList = new ArrayList<>();
        Optional.ofNullable(reportMaps)
                .ifPresent(maps -> maps.forEach(reportMap -> {
                    String groupTag = Optional.ofNullable(reportMap.get("groupTag"))
                            .map(Object::toString)
                            .orElse("");
                    String count = Optional.ofNullable(reportMap.get("count"))
                            .map(Object::toString)
                            .orElse("");

                    xList.add(groupTag);
                    yList.add(count);
                }));

        xyMap.put("xList", xList);
        xyMap.put("yList", yList);
        String countColumn = vectorData.getCountKeyword();
        switch (countColumn) {
            case "user_id":
                xyMap.put("yName", "人数(人)");
                break;
            case "order_id":
                xyMap.put("yName", "销售量(单)");
                break;
            default:
                xyMap.put("yName", "销售额(元)");
        }
        return xyMap;
    }


    private VOrderInfoJsonObject getVectorData(VOrderInfoJsonObject vOrderInfoJsonObject) {
        // 1. 聚合关键词
        CompletableFuture<Void> columnFuture = CompletableFuture.runAsync(() -> {
            String countKeyword = vOrderInfoJsonObject.getCountKeyword();
            Map<String, String> countEmbeddings = PineconeSimilarlyUtil.getPineconeSimilarityEmbeddings(countKeyword, PineconeConst.COUNT_KEY_INDEX);
            String countColumn = countEmbeddings.get("column").trim();
            vOrderInfoJsonObject.setCountKeyword(StringUtils.hasText(countColumn) ? countColumn : "order_amount");
        }, threadPoolExecutor);

        // 2. 分组关键词
        CompletableFuture<Void> groupFuture = CompletableFuture.runAsync(() -> {
            String groupKeyword = vOrderInfoJsonObject.getGroupKeyword();
            Map<String, String> groupEmbeddings = PineconeSimilarlyUtil.getPineconeSimilarityEmbeddings(groupKeyword, PineconeConst.GROUP_KEY_INDEX);
            String groupColumn = groupEmbeddings.get("column").trim();
            vOrderInfoJsonObject.setGroupKeyword(StringUtils.hasText(groupColumn) ? groupColumn : "create_date");
        }, threadPoolExecutor);

        // 3. 条件关键词（地区、品牌、商品）仅在 keyword 存在时创建异步任务
        CompletableFuture<Void> provinceNameFuture = processKeywordAsync(
                vOrderInfoJsonObject::getProvinceName,
                vOrderInfoJsonObject::setProvinceName,
                PineconeConst.SELECT_KEY_INDEX
        );

        CompletableFuture<Void> tmNameFuture = processKeywordAsync(
                vOrderInfoJsonObject::getTmName,
                vOrderInfoJsonObject::setTmName,
                PineconeConst.SELECT_KEY_INDEX
        );

        CompletableFuture<Void> skuNameFuture = processKeywordAsync(
                vOrderInfoJsonObject::getSkuName,
                vOrderInfoJsonObject::setSkuName,
                PineconeConst.SELECT_KEY_INDEX
        );

        // 等待所有任务完成
        CompletableFuture.allOf(
                columnFuture,
                groupFuture,
                provinceNameFuture,
                tmNameFuture,
                skuNameFuture
        ).join();

        return vOrderInfoJsonObject;
    }

    private CompletableFuture<Void> processKeywordAsync(
            Supplier<String> getter,
            Consumer<String> setter,
            String pineconeIndex
    ) {
        String keyword = getter.get();
        if (!StringUtils.hasText(keyword)) {
            return CompletableFuture.completedFuture(null);
        }

        return CompletableFuture.runAsync(() -> {
            try {
                Map<String, String> embeddings = PineconeSimilarlyUtil.getPineconeSimilarityEmbeddings(keyword, pineconeIndex);
                String word = embeddings.get("word");
                if (word != null) {
                    word = word.trim();
                    if (StringUtils.hasText(word)) {
                        setter.accept(word);
                    }
                }
            } catch (Exception e) {
                // 记录日志
                log.error("处理关键词异常", e);
            }
        }, threadPoolExecutor);
    }


    private QueryWrapper<VOrderInfo> getReportWrapper(QueryWrapper<VOrderInfo> queryWrapper, VOrderInfoJsonObject vectorData) {
        // 1. 聚合字段处理
        String countKeySql;
        String countColumn = vectorData.getCountKeyword();
        if ("order_amount".equals(countColumn)) {
            countKeySql = "sum(" + countColumn + ") as count";
        } else {
            countKeySql = "count(DISTINCT " + countColumn + ") as count";
        }

        // 2. 分组字段处理
        String groupKeySql;
        String groupColumn = vectorData.getGroupKeyword();
        if ("create_date".equals(groupColumn)) {
            groupKeySql = "date_format(" + groupColumn + ",'%Y-%m-%d')";
        } else {
            groupKeySql = groupColumn;
        }

        // 3. 拼接sql
        String provinceName = vectorData.getProvinceName();
        String skuName = vectorData.getSkuName();
        String tmName = vectorData.getTmName();
        queryWrapper.select(groupKeySql + " as groupTag", countKeySql)
                .eq(StringUtils.hasText(provinceName), "province_name", provinceName)
                .eq(StringUtils.hasText(skuName), "sku_name", skuName)
                .eq(StringUtils.hasText(tmName), "tm_name", tmName)
                .groupBy(groupKeySql);
        return queryWrapper;
    }
}
